//设计一个支持下述操作的食物评分系统： 
//
// 
// 修改 系统中列出的某种食物的评分。 
// 返回系统中某一类烹饪方式下评分最高的食物。 
// 
//
// 实现 FoodRatings 类： 
//
// 
// FoodRatings(String[] foods, String[] cuisines, int[] ratings) 初始化系统。食物由 
//foods、cuisines 和 ratings 描述，长度均为 n 。 
// 
//
// 
// foods[i] 是第 i 种食物的名字。 
// cuisines[i] 是第 i 种食物的烹饪方式。 
// ratings[i] 是第 i 种食物的最初评分。 
// 
// 
// void changeRating(String food, int newRating) 修改名字为 food 的食物的评分。 
// String highestRated(String cuisine) 返回指定烹饪方式 cuisine 下评分最高的食物的名字。如果存在并列，返回 字典
//序较小 的名字。 
//
//
// 注意，字符串 x 的字典序比字符串 y 更小的前提是：x 在字典中出现的位置在 y 之前，也就是说，要么 x 是 y 的前缀，或者在满足 x[i] != 
//y[i] 的第一个位置 i 处，x[i] 在字母表中出现的位置在 y[i] 之前。 
//
// 
//
// 示例： 
//
// 输入
//["FoodRatings", "highestRated", "highestRated", "changeRating", 
//"highestRated", "changeRating", "highestRated"]
//[[["kimchi", "miso", "sushi", "moussaka", "ramen", "bulgogi"], ["korean", 
//"japanese", "japanese", "greek", "japanese", "korean"], [9, 12, 8, 15, 14, 7]], [
//"korean"], ["japanese"], ["sushi", 16], ["japanese"], ["ramen", 16], ["japanese"]]
//输出
//[null, "kimchi", "ramen", null, "sushi", null, "ramen"]
//
//解释
//FoodRatings foodRatings = new FoodRatings(["kimchi", "miso", "sushi", 
//"moussaka", "ramen", "bulgogi"], ["korean", "japanese", "japanese", "greek", "japanese",
// "korean"], [9, 12, 8, 15, 14, 7]);
//foodRatings.highestRated("korean"); // 返回 "kimchi"
//                                    // "kimchi" 是分数最高的韩式料理，评分为 9 。
//foodRatings.highestRated("japanese"); // 返回 "ramen"
//                                      // "ramen" 是分数最高的日式料理，评分为 14 。
//foodRatings.changeRating("sushi", 16); // "sushi" 现在评分变更为 16 。
//foodRatings.highestRated("japanese"); // 返回 "sushi"
//                                      // "sushi" 是分数最高的日式料理，评分为 16 。
//foodRatings.changeRating("ramen", 16); // "ramen" 现在评分变更为 16 。
//foodRatings.highestRated("japanese"); // 返回 "ramen"
//                                      // "sushi" 和 "ramen" 的评分都是 16 。
//                                      // 但是，"ramen" 的字典序比 "sushi" 更小。
// 
//
// 
//
// 提示： 
//
// 
// 1 <= n <= 2 * 10⁴ 
// n == foods.length == cuisines.length == ratings.length 
// 1 <= foods[i].length, cuisines[i].length <= 10 
// foods[i]、cuisines[i] 由小写英文字母组成 
// 1 <= ratings[i] <= 10⁸ 
// foods 中的所有字符串 互不相同 
// 在对 changeRating 的所有调用中，food 是系统中食物的名字。 
// 在对 highestRated 的所有调用中，cuisine 是系统中 至少一种 食物的烹饪方式。 
// 最多调用 changeRating 和 highestRated 总计 2 * 10⁴ 次 
// 
//
// Related Topics 设计 数组 哈希表 字符串 有序集合 堆（优先队列） 👍 47 👎 0


package LeetCode.editor.cn;


import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ldltd
 * @date 2025-02-28 09:02:43
 * @description 2353.设计食物评分系统
 
 */
 
public class DesignAFoodRatingSystem {
    public static void main(String[] args) {
    //测试代码
    DesignAFoodRatingSystem fun = new DesignAFoodRatingSystem();

    
    }

//leetcode submit region begin(Prohibit modification and deletion)
    //思路1，记录每种食物的类型，但是每种类型只维护一个有序的集合或者堆
    //改变时判断对应类型集合的最大元素是否比当前元素小，如果是，则清空列表，如果相等，则按字典序加入集合，否则删除
class FoodRatings {
    Map<String,Pair<Integer,String>> foodsMap;
    Map<String, TreeSet<Pair<Integer,String>>> rateMap;
    private int n;
    public FoodRatings(String[] foods, String[] cuisines, int[] ratings) {
         n = foods.length;
         foodsMap=new HashMap<>();
         rateMap=new HashMap<>();
        for (int i = 0; i < n; i++) {
            String food=foods[i];
            String cuisine=cuisines[i];
            int rate=ratings[i];
            foodsMap.put(food,new Pair<>(rate,cuisine));
            //
            rateMap.computeIfAbsent(cuisine,k->new TreeSet<>((a,b)->{
                if(!a.getKey().equals(b.getKey())){
                    return a.getKey()-b.getKey();
                }
                return a.getValue().compareTo(b.getValue());
            })).add(new Pair<>(n-rate,food));
        }

    }
    
    public void changeRating(String food, int newRating) {
        Pair<Integer, String> pair = foodsMap.get(food);
        int oldRating=pair.getKey();
        String cuisine=pair.getValue();
        rateMap.get(cuisine).remove(new Pair<>(n-oldRating,food));
        rateMap.get(cuisine).add(new Pair<>(n-newRating,food));
        foodsMap.put(food,new Pair<>(newRating,cuisine));
    }
    
    public String highestRated(String cuisine) {
        return rateMap.get(cuisine).first().getValue();
    }
    class Pair<T, S> {
        private final T first;
        private final S second;

        public Pair(T first, S second) {
            this.first = first;
            this.second = second;
        }

        public T getKey() { // Java 里的 Pair 一般用 getKey() 和 getValue()
            return first;
        }

        public S getValue() {
            return second;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Pair<?, ?> pair = (Pair<?, ?>) o;
            return first.equals(pair.first) && second.equals(pair.second);
        }

        @Override
        public int hashCode() {
            return Objects.hash(first, second);
        }
    }

}

/**
 * Your FoodRatings object will be instantiated and called as such:
 * FoodRatings obj = new FoodRatings(foods, cuisines, ratings);
 * obj.changeRating(food,newRating);
 * String param_2 = obj.highestRated(cuisine);
 */
//leetcode submit region end(Prohibit modification and deletion)

}
